package com.deodar.kettle.platform.monitor.service;

import com.deodar.kettle.platform.common.util.JSONObject;
import com.deodar.kettle.platform.common.util.KettleEncr;
import com.deodar.kettle.platform.common.vo.CarteStatusVo;
import com.deodar.kettle.platform.database.domain.RSlave;
import com.deodar.kettle.platform.database.domain.RnStepStatus;
import com.deodar.kettle.platform.database.service.IRSlaveService;
import com.deodar.kettle.platform.monitor.util.CarteClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.pentaho.di.cluster.SlaveServer;
import org.pentaho.di.trans.step.StepStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: Administrator
 * @Description:
 * @version: 1.0.0
 */
@Slf4j
@Service("slaveService")
public class SlaveService {

    @Autowired
    IRSlaveService rSlaveService;

    public SlaveServer getMinLoad() throws Exception{
        RSlave slaveInfo =  getMinRSlave();
        return getSlaveServer(slaveInfo);
    }

    public void add(RSlave slaveInfo){
        rSlaveService.insertRSlave(slaveInfo);
    }

    public void update(RSlave slaveInfo){
        rSlaveService.updateRSlave(slaveInfo);
    }

    public void delete(Integer id){
        rSlaveService.deleteRSlaveById(id);
    }

    public RSlave getMinRSlave() throws Exception{

        List<RSlave> slaves = rSlaveService.getAllSlaveInfo();
        try {
            List<RSlave> allSlave = setLoadAvgAndStatus(slaves);

            RSlave slaveServer = getSlaveByLoadAvg(allSlave);

            return slaveServer;
        } catch (Exception e) {
             throw e;
        }

    }

    /**
     * 测试指定服务是否可用
     * @param id
     * @return
     * @throws Exception
     */
    public JSONObject testSlave(Integer id) throws Exception{
        RSlave slave = rSlaveService.selectRSlaveById(id);
        JSONObject json=new JSONObject();

        slave.setPassword(KettleEncr.decryptPasswd(slave.getPassword()));
        CarteClient cc=new CarteClient(slave);
        boolean isActive=cc.isActive();
        int timeOut=3000;
        boolean slaveNetStatus= InetAddress.getByName(slave.getHostName()).isReachable(timeOut);

        if(isActive && slaveNetStatus){
            json.put("carteStatus","Y");

        }else{
            json.put("carteStatus","N");

        }

        return json;
    }

    private SlaveServer getSlaveServer(RSlave slave) {
        SlaveServer remoteSlaveServer = new SlaveServer();
        remoteSlaveServer.setName(slave.getName());
        remoteSlaveServer.setHostname(slave.getHostName());
        remoteSlaveServer.setMaster(true);
        remoteSlaveServer.setPort(slave.getPort());
        remoteSlaveServer.setUsername(slave.getUsername());
        remoteSlaveServer.setPassword(slave.getPassword());

        return  remoteSlaveServer;
    }

    public RnStepStatus getRnStepStatus(StepStatus baseStep){
        RnStepStatus RnStepStatus = new RnStepStatus();
        RnStepStatus.setCopy(baseStep.getCopy());
        RnStepStatus.setLinesRead(baseStep.getLinesRead());
        RnStepStatus.setStepName(baseStep.getStepname());
        RnStepStatus.setLinesWritten(baseStep.getLinesWritten());
        RnStepStatus.setLinesInput(baseStep.getLinesInput());

        RnStepStatus.setLinesOutput(baseStep.getLinesOutput());
        RnStepStatus.setLinesUpdated(baseStep.getLinesUpdated());
        RnStepStatus.setLinesRejected(baseStep.getLinesRejected());
        RnStepStatus.setLogErrors(baseStep.getErrors());
        RnStepStatus.setStatusDescription(baseStep.getStatusDescription());


        RnStepStatus.setLogSeconds(baseStep.getSeconds());
        RnStepStatus.setSpeed(baseStep.getSpeed());
        RnStepStatus.setLogPriority(baseStep.getPriority());
        RnStepStatus.setStopped(baseStep.isStopped() == true ? "N":"Y");
        RnStepStatus.setPaused(baseStep.isPaused() == true ? "N":"Y");

        return RnStepStatus;

    }

    public List<RSlave> setLoadAvgAndStatus(List<RSlave> slaves) throws Exception{
        List<RSlave> result=new ArrayList<>();
        for(RSlave slave:slaves){
            //对取出的节点密码进行解码重新赋值
            slave.setPassword(KettleEncr.decryptPasswd(slave.getPassword()));
            //获取节点状态的相关信息
            CarteClient carteClient=new CarteClient(slave);
            String status= null;
            status=carteClient.getStatusOrNull();
            boolean dbActive =!carteClient.isDBActive();
            CarteStatusVo carteStatusVo = null;
            if (status != null) {
                if (dbActive) {
                    carteStatusVo = CarteStatusVo.parseXml(status);
                    //设置负载以及节点是否正常
                    slave.setLoadAvg(carteStatusVo.getLoadAvg()+1.2);
                    slave.setRunStatus("<font color='green'>节点正常</font>");
                } else {

                    slave.setLoadAvg(-1);
                    slave.setRunStatus("<font color='red'>该节点连接资源数据库异常</font>");
                }

            } else {
                slave.setLoadAvg(-1);
                slave.setRunStatus("<font color='red'>节点异常</font>");

            }
            result.add(slave);
        }
        return result;
    }

    private RSlave getSlaveByLoadAvg(List<RSlave> slaves) throws Exception {
        RSlave minSlave=null;
        List<RSlave> errorSlaves=new ArrayList<>();
        if(slaves!=null && slaves.size()>0){
            //获取不正常节点
            for(int i=0;i<slaves.size();i++){
                if (slaves.get(i).getLoadAvg()< 0){
                    errorSlaves.add(slaves.get(i));
                }
            }
            //移除不正常节点
            for(RSlave errorSlave:errorSlaves){
                slaves.remove(errorSlave);
            }
            //从正常节点中获取负载指数最低的节点
            if(slaves.size()==1){
                minSlave=slaves.get(0);
            }else if(slaves.size()>1){
                minSlave=slaves.get(0);
                for(int i=0;i<slaves.size();i++){
                    if (slaves.get(i).getLoadAvg()<minSlave.getLoadAvg()){
                        minSlave=slaves.get(i);
                    }
                }
            }
        }
        return minSlave;
    }
}
